package com.apache.rpc.util;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import net.sf.json.JSONArray;
import net.sf.json.xml.XMLSerializer;

import org.apache.log4j.Logger;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.input.SAXBuilder;
import org.jdom.output.Format;
import org.jdom.output.XMLOutputter;

import com.apache.exception.BusinessException;
import com.apache.rpc.entity.Protocol;

public class XMLMapParse {

	private Logger log = Logger.getLogger(XMLMapParse.class);

	private static XMLMapParse instance;

	private XMLMapParse() {
	}

	public static XMLMapParse instance() {
		if (null == instance) {
			instance = new XMLMapParse();
		}
		return (instance);
	}

	/**
	 * TODO 生成xml的报文 
	 */
	public String buildSingleXML(Protocol protocol) {

		try {
			Element root = builderHeaderInfo(protocol.getReqFlag(), protocol.getBeanId(), protocol.getRespType(),
					protocol.getIsClose(), getDefaultStr(protocol.getProtocolType(), "socket"));

			Element body = new Element("Body"); // 生成元素：Body

			addElementToBody(body, protocol.getParams());
			root.addContent(body);
			return elementToString(root);

		} catch (Exception e) {
			log.info("构造交易报文出现错误:reqFlag=" + protocol.getReqFlag() + ",BeanId=" + protocol.getBeanId(), e);
		}
		return "";

	}

	/**
	 * 函数名称： xmlGetData 函数功能： 解析后台返回的xml报文,将结果保存在ArrayList数组 参数说明：
	 * @param xmldata: xml字符串。
	 */
	@SuppressWarnings("rawtypes")
	public void xmlGetData(String xmldata, Map<String, Object> headMap, Map<String, Object> bodyMap) {
		try {
			xmldata = xmldata.trim();
			SAXBuilder builder = new SAXBuilder();
			Reader in_xml = new StringReader(xmldata);
			Document doc = builder.build(in_xml);// "c:\\xml\\getxml_doc.xml"
			if (null == doc) {
				log.info("报文解析错误,报文内容为空");
				throw new BusinessException("报文内容为空");
			}
			Element e0 = doc.getRootElement();
			if (null == e0) {
				log.info("报文解析错误,报文内容为空");
				throw new BusinessException("报文内容为空");
			}
			List list1 = e0.getChildren("Head");
			List list2 = e0.getChildren("Body");// Root-->Body 获得指定名称子元素的List
			if (list1 == null || list2 == null) {
				log.info("报文解析错误,报文格式不符合规范");
				throw new BusinessException("报文格式不符合规范");
			}
			// 在head里边查找xmlTagName
			if (list1 != null) {
				Element e_txf = (Element) list1.get(0);
				if (!isNull(e_txf.getChildText("MethodCode"))) {
					headMap.put("MethodCode", e_txf.getChildText("MethodCode"));
				}
				if (!isNull(e_txf.getChildText("BeanId"))) {
					headMap.put("BeanId", e_txf.getChildText("BeanId"));
				}
				if (!isNull(e_txf.getChildText("ParamType"))) {
					headMap.put("ParamType", e_txf.getChildText("ParamType"));
				}
				if (!isNull(e_txf.getChildText("SocketClose"))) {
					headMap.put("SocketClose", e_txf.getChildText("SocketClose"));
				}
			}

			if (list2 != null) {
				Element e_rmsg = (Element) list2.get(0);// 获得Body元素,假如Root下有多个Body，我们只取第一个Body.
				List list3 = e_rmsg.getChildren();
				if (!isEmpty(list3)) {
					int count = list3.size();
					for (int i = 0; i < count; i++) {
						Element elt = (Element) list3.get(i);
						if (!isEmpty(elt.getChildren())) {
							bodyMap.put(elt.getName(), xmlToJavaBean(elt.getChildren()));
						} else {
							bodyMap.put(elt.getName(), elt.getText());
						}
					}
				}
			}
		} catch (Exception e) {
			log.info("解析应答报文出现错误", e);
		}
	}

	public String jsonToXMl(String json) {
		XMLSerializer xmlSerializer = new XMLSerializer();
		String str = xmlSerializer.write(JSONArray.fromObject(json)).toString();
		str = str.replaceAll("<a>", "<xml-body>");
		str = str.replaceAll("</a>", "</xml-body>");
		str = str.replaceAll("</e>", "");
		str = str.replaceAll(" type=\"string\"", "");
		str = str.replaceAll(" class=\"object\"", "");
		int dd = str.indexOf("<xml-body>");
		str = str.substring(0, dd + 10) + str.substring(dd + 13);
		return str;
	}

	@SuppressWarnings({ "rawtypes", "unchecked" })
	private List xmlToJavaBean(List list) {
		List result = new ArrayList();
		int count = list.size();
		for (int i = 0; i < count; i++) {
			Element elt = (Element) list.get(i);
			if ("list".equals(elt.getName())) {
				List list3 = elt.getChildren();
				if (isEmpty(list3)) {
					result.add(elt.getText());
				} else {
					for (int j = 0; j < list3.size(); j++) {
						Element elt2 = (Element) list3.get(j);
						result.add(elt2.getText());
					}
				}
			} else {
				Map<String, String> map = new HashMap<String, String>();
				List list3 = elt.getChildren();
				if (isEmpty(list3)) {
					map.put(elt.getName(), elt.getText());
				} else {
					for (int j = 0; j < list3.size(); j++) {
						Element elt2 = (Element) list3.get(j);
						map.put(elt2.getName(), elt2.getText());
					}
				}
				result.add(map);
			}
		}
		return result;
	}

	/**
	 * 函数名称： xmlGetData 函数功能： 解析后台返回的xml报文,将结果保存在ArrayList数组 参数说明：
	 * @param xmldata: xml字符串。
	 */
	@SuppressWarnings("rawtypes")
	public void xmlGetDataToHead(String xmldata, Map<String, Object> headMap) {
		try {
			xmldata = xmldata.trim();
			SAXBuilder builder = new SAXBuilder();
			Reader in_xml = new StringReader(xmldata);
			Document doc = builder.build(in_xml);// "c:\\xml\\getxml_doc.xml"
			Element e0 = doc.getRootElement();
			if (doc == null || e0 == null) {
				log.info("报文解析错误,报文内容为空");
				throw new BusinessException("报文内容为空");
			}
			List list1 = e0.getChildren("Head");
			if (list1 == null) {
				log.info("报文解析错误,报文格式不符合规范");
				throw new BusinessException("报文格式不符合规范");
			}
			// 在head里边查找xmlTagName
			if (list1 != null) {
				Element e_txf = (Element) list1.get(0);
				if (!isNull(e_txf.getChildText("MethodCode"))) {
					headMap.put("MethodCode", e_txf.getChildText("MethodCode"));
				}
				if (!isNull(e_txf.getChildText("BeanId"))) {
					headMap.put("BeanId", e_txf.getChildText("BeanId"));
				}
				if (!isNull(e_txf.getChildText("ParamType"))) {
					headMap.put("ParamType", e_txf.getChildText("ParamType"));
				}
				if (!isNull(e_txf.getChildText("SocketClose"))) {
					headMap.put("SocketClose", e_txf.getChildText("SocketClose"));
				}
				if (!isNull(e_txf.getChildText("ProtocolType"))) {
					headMap.put("ProtocolType", e_txf.getChildText("ProtocolType"));
				} else {
					headMap.put("ProtocolType", "socket");
				}

			}
		} catch (Exception e) {
			log.info("解析应答报文出现错误", e);
		}
	}

	private Element builderHeaderInfo(String methodCode, String beanId, String paramtype, String isClose,
			String protocolType) {
		Element root, head;
		Element hVersion, hPCode, hParamType, hBeanId, hSocketCLose, protocolTypee;

		root = new Element("xml-body"); // 生成根元素：Root
		head = new Element("Head"); // 生成元素：Head

		hVersion = new Element("Version");
		hPCode = new Element("MethodCode");
		hBeanId = new Element("BeanId");
		hParamType = new Element("ParamType");
		protocolTypee = new Element("ProtocolType");
		hSocketCLose = new Element("SocketClose");

		hVersion.setText("1.0");
		hPCode.setText(methodCode);
		hBeanId.setText(beanId);
		hParamType.setText(paramtype);
		hSocketCLose.setText(isClose);
		protocolTypee.setText(protocolType);

		head.addContent(hVersion);
		head.addContent(hPCode);
		head.addContent(hBeanId);
		head.addContent(hParamType);
		head.addContent(hSocketCLose);
		head.addContent(protocolTypee);
		root.addContent(head);
		return root;
	}

	private String elementToString(Element root) throws BusinessException, FileNotFoundException, IOException {
		Document doc = new Document(root);
		String xmlfilename;
		Format format = Format.getRawFormat();
		format.setEncoding("UTF-8"); // 设置xml文件的字符为gb2312
		format.setIndent("    "); // 设置xml文件的缩进为4个空格
		XMLOutputter XMLOut = new XMLOutputter(format);// 元素后换行一层元素缩四格
		xmlfilename = XMLOut.outputString(doc);
		//xmlfilename = xmlfilename.replaceAll("encoding=\"UTF-8\"", "encoding=\"UTF-8\"");
		return xmlfilename;
	}

	@SuppressWarnings({ "rawtypes", "unchecked" })
	private void addElementToBody(Element eBody, Map<String, Object> tranMap) throws Exception {
		Element element_tmp;
		for (String key : tranMap.keySet()) {
			if (!isNull(key) && !isEmpty(tranMap.get(key))) {
				element_tmp = new Element(key);
				String keyValueClass = tranMap.get(key).getClass().getSimpleName();
				if ("ArrayList".equals(keyValueClass) || "List".equals(keyValueClass)) {
					String valueClass = ((List) tranMap.get(key)).get(0).getClass().getSimpleName();
					if ("String".equals(valueClass)) {
						addElementsToBodyList(element_tmp, (List) tranMap.get(key));
					} else {
						addElementsToBody(element_tmp, (List) tranMap.get(key));
					}
				} else if ("Map".equalsIgnoreCase(keyValueClass) || "HashMap".equalsIgnoreCase(keyValueClass)) {
					addElementsToBodyMap(element_tmp, (Map) tranMap.get(key));
				} else {
					String keyValue = String.valueOf(tranMap.get(key));
					element_tmp.setText(keyValue);
				}
				eBody.addContent(element_tmp);
			} else {
				continue;
			}
		}
	}

	private void addElementsToBodyMap(Element eBody, Map<String, List<String>> tranList) {
		if (!isEmpty(tranList)) {
			Element element_tmp;
			for (String key : tranList.keySet()) {
				List<String> tranMap = tranList.get(key);
				if (!isEmpty(tranMap)) {//list数据
					Element map_tmp = new Element("list");
					for (String keyStr : tranMap) {
						if (!isNull(key)) {
							element_tmp = new Element("String");
							element_tmp.setText(keyStr);
							map_tmp.addContent(element_tmp);
						} else {
							log.info("body字段名称错误:空字串");
							throw new BusinessException("body字段名称错误:空字串");
						}
					}
					eBody.addContent(map_tmp);
				} else {//map数据
					String keyValueClass = tranList.get(key).getClass().getSimpleName();
					if ("Map".equalsIgnoreCase(keyValueClass) || "HashMap".equalsIgnoreCase(keyValueClass)) {
						Element map_tmp = new Element("map");
						Map<String, Object> tranMap2 = (Map<String, Object>) tranList.get(key);
						for (String key2 : tranMap2.keySet()) {
							if (!isNull(key2)) {
								element_tmp = new Element(key2);
								String keyValue = String.valueOf(tranMap2.get(key2));
								element_tmp.setText(keyValue);
								map_tmp.addContent(element_tmp);
							} else {
								log.info("body字段名称错误:空字串");
							}
						}
						eBody.addContent(map_tmp);
					}
				}
			}
		}
	}

	private void addElementsToBody(Element eBody, List<Map<String, Object>> tranList) {
		if (!isEmpty(tranList)) {
			int count = tranList.size();
			for (int i = 0; i < count; i++) {
				Element element_tmp;
				Element map_tmp = new Element("map");
				Map<String, Object> tranMap = tranList.get(i);
				for (String key : tranMap.keySet()) {
					if (!isNull(key)) {
						element_tmp = new Element(key);
						String keyValue = String.valueOf(tranMap.get(key));
						element_tmp.setText(keyValue);
						map_tmp.addContent(element_tmp);
					} else {
						log.info("body字段名称错误:空字串");
						throw new BusinessException("body字段名称错误:空字串");
					}
				}
				eBody.addContent(map_tmp);
			}
		}
	}

	private void addElementsToBodyList(Element eBody, List<String> tranList) {
		if (!isEmpty(tranList)) {
			Element map_tmp = new Element("list");
			for (String key : tranList) {
				if (!isNull(key)) {
					Element element_tmps = new Element("String");
					element_tmps.setText(key);
					map_tmp.addContent(element_tmps);
				} else {
					log.info("body字段名称错误:空字串");
					throw new BusinessException("body字段名称错误:空字串");
				}
			}
			eBody.addContent(map_tmp);
		}
	}

	/**
	 *判断对象数组是否为空
	 * 
	 * @param  object 对象数组
	 * @return        如果object为空返回true，不为空返回false 
	 */
	public boolean isNull(Object[] object) {
		if (object == null || object.length == 0) {
			return true;
		} else {
			return false;
		}
	}

	/**
	 *判断一个字符串是否为空
	 * 
	 * @param  str 传入的字符串
	 * @return     如果str为空返回true，不为空返回false 
	 */
	public boolean isNull(String str) {
		if (str == null) {
			return true;
		}
		str = str.trim();
		if ((str.equals("null")) || (str.equals(""))) {
			return true;
		}
		return false;
	}

	/**
	 *判断对象是否为空
	 * 
	 * @param  obj 传入的对象
	 * @return     如果obj为空返回true，不为空返回false  
	 */
	public boolean isEmpty(Object obj) {
		return obj == null;
	}

	/**
	 * 判断一个list集合是否为空
	 * 
	 * @param  list    传入的list
	 * @return         如果list为空或者长度为0返回true，不为空返回false  
	 */
	public boolean isEmpty(List list) { //
		return list == null || list.size() == 0;
	}

	private String getDefaultStr(String text, String defaultStr) {
		if (isNull(text))
			return defaultStr;
		return text;
	}

	/**
	 * 判断一个list集合是否为空
	 * 
	 * @param  collection 传入的集合
	 * @return            如果collection为空或者长度为0返回true，不为空返回false  
	 */
	private boolean isEmpty(Collection collection) { //
		return collection == null || collection.isEmpty();
	}

	public static void main(String[] args) {
		//		String json2 = "<?xml version='1.0' encoding='UTF-8'?><xml-body><Head><Version>1.0</Version><MethodCode>getDealmakingData</MethodCode><BeanId>dealmakingService</BeanId><ParamType>XML</ParamType></Head><Body><tradeId>E0000001243</tradeId><prodId>P0031</prodId></Body></xml-body>";
		//		String json = "[{\"Head\":{\"MethodCode\":\"getDealmakingData\",\"BeanId\":\"dealmakingService\",\"ParamType\":\"json\"},\"Body\":{\"tradeId\":\"E0000001243\",\"prodId\":\"P0031\",\"prodId2\":\"P0031\"}}]";
		//		if (!json2.startsWith("<?xml "))
		//			System.out.println(json2);
		//		else {
		//			System.out.println(XMLMapParse.instance().jsonToXMl(json));
		//		}
		//		System.out.println(DateUtils.longToStr(1416217220228l, FmtStr.yyyyMMdd_HHmmss));
		//		Protocol pl = new Protocol();
		//		pl.setBeanId("beanId");
		//		pl.setReqFlag("reqFlag");
		//		pl.setRespType("XML");
		//		List list = new ArrayList();
		//		for (int i = 0; i < 10; i++) {
		//			list.add("list-" + i);
		//		}
		//		//pl.setParams("pList", list);
		//		pl.setParams("ddd", "value");
		//		Map map = new HashMap();
		//		map.put("key001", list);
		//		map.put("key002", list);
		//		//map.put("key002", "value-002");
		//		//map.put("key003", "value-003");
		//		pl.setParams(map);
		//		String xml = XMLMapParse.instance().buildSingleXML(pl);
		//		System.out.println(xml);
		//		Map<String, Object> headMap = new HashMap<String, Object>();
		//		Map<String, Object> bodyMap = new HashMap<String, Object>();
		//		XMLMapParse.instance().xmlGetData(xml, headMap, bodyMap);
		//		System.out.println(headMap);
	}
}
